/*
 * Copyright (C) 2022-2022. Huawei Technologies Co., Ltd. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.openlookeng.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.openlookeng.core.boot.dto.LoginUserInfoDTO;
import com.openlookeng.core.boot.jwt.model.Audience;
import com.openlookeng.core.boot.utils.Constant;
import com.openlookeng.core.boot.utils.JwtTokenUtil;
import com.openlookeng.core.dto.SshUserDTO;
import com.openlookeng.core.mp.base.BaseServiceImpl;
import com.openlookeng.core.tool.Md5Utils;
import com.openlookeng.dto.AddClusterDTO;
import com.openlookeng.dto.ClusterChartInfoDTO;
import com.openlookeng.dto.EchartTimeDTO;
import com.openlookeng.dto.OpenlookengClusterDTO;
import com.openlookeng.entity.Ecs;
import com.openlookeng.entity.OpenlookengCluster;
import com.openlookeng.entity.OpenlookengClusterConfig;
import com.openlookeng.entity.SysFile;
import com.openlookeng.enums.ConfigSynStateEnum;
import com.openlookeng.enums.ConfigTypeEnum;
import com.openlookeng.enums.NodeTypeEnum;
import com.openlookeng.exception.BizException;
import com.openlookeng.mapper.OpenlookengClusterMapper;
import com.openlookeng.qo.HostStatusAndTypeQo;
import com.openlookeng.qo.OpenlookengClusterQO;
import com.openlookeng.service.IEcsService;
import com.openlookeng.service.IFileService;
import com.openlookeng.service.IOpenLookengService;
import com.openlookeng.service.IOpenlookengClusterConfigService;
import com.openlookeng.service.IOpenlookengClusterService;
import com.openlookeng.vo.ClusterItemVO;
import com.openlookeng.vo.ClusterStateGeneralVO;
import com.openlookeng.vo.ClusterStateVO;
import com.openlookeng.vo.NodeItemVO;
import com.openlookeng.vo.OpenlookengClusterVO;
import com.openlookeng.wrapper.OpenlookengClusterWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OpenlookengClusterServiceImpl
        extends BaseServiceImpl<OpenlookengClusterMapper, OpenlookengCluster>
        implements IOpenlookengClusterService
{
    @Autowired
    private Audience audience;

    @Resource
    private IEcsService iEcsService;

    @Resource
    private IOpenlookengClusterConfigService configService;

    @Resource
    private IFileService iFileService;

    @Autowired
    @Lazy
    private IOpenLookengService openLookengService;

    @Resource
    private CacheManager cacheManager;

    @Override
    public IPage<OpenlookengClusterVO> selectOpenlookengClusterPage(OpenlookengClusterQO qo)
    {
        SysFile sysFile = iFileService.listFileBySystemUpLoad().get(0);
        String newVersion = sysFile.getVersion();
        LoginUserInfoDTO currentLoginUser = JwtTokenUtil.getCurrentLoginUser(audience);
        qo.setCreateUserId(Integer.parseInt(currentLoginUser.getId()));
        QueryWrapper<OpenlookengCluster> queryWrapper = this.getQueryChainWrapper(qo);
        IPage<OpenlookengClusterVO> page = OpenlookengClusterWrapper.build().pageVO(this.page(new Page<>(qo.getPageNo(), qo.getPageSize()), queryWrapper));
        List<Ecs> list = iEcsService.list(null);
        page.getRecords().forEach(item -> {
            Ecs ecs = list.stream().filter(ite -> ite.getId().equals(item.getEcsId())).findFirst().orElse(null);
            item.setServerIp(ecs.getIp());
        });
        if (StrUtil.isNotEmpty(qo.getIp())) {
            page.setRecords(page.getRecords().stream().filter(item -> item.getServerIp().contains(qo.getIp())).collect(Collectors.toList()));
        }
        List<Integer> escIdList = page.getRecords().stream().map(a -> a.getEcsId()).distinct().collect(Collectors.toList());
        if (escIdList.isEmpty()) {
            return page;
        }
        List<Ecs> ecsList = iEcsService.listByIds(escIdList);

        List<OpenlookengClusterVO> records = page.getRecords();
        List<Integer> clusterIds = records.stream().map(item -> item.getId()).distinct().collect(Collectors.toList());
        LambdaQueryWrapper<OpenlookengClusterConfig> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OpenlookengClusterConfig::getClusterCode, currentLoginUser.getId());
        wrapper.in(OpenlookengClusterConfig::getOpenlookengClusterId, clusterIds);
        wrapper.eq(OpenlookengClusterConfig::getProKeyName, Constant.HTTP_SERVER_HTTP_PORT.getCode());
        List<OpenlookengClusterConfig> configs = configService.list(wrapper);

        //Filter coordination node
        List<OpenlookengClusterVO> coorUrl = records.stream().filter(item -> !Constant.NODE_TYPE_1.getCode().equalsIgnoreCase(item.getNodeType()) && !Constant.NODE_TYPE_4.getCode().equalsIgnoreCase(item.getNodeType())).collect(Collectors.toList());

        List<String> addresss = new ArrayList<>();
        coorUrl.forEach(item -> {
            Ecs ecs = ecsList.stream().filter(t -> t.getId().equals(item.getEcsId())).findFirst().get();
            OpenlookengClusterConfig config = configs.stream().filter(it -> item.getVersion().equals(it.getVersion()) && it.getOpenlookengClusterId().equals(item.getId())).findFirst().orElse(null);
            String port = null;
            String addr = null;
            if (ObjectUtil.isNotEmpty(config)) {
                port = config.getProValue();
                addr = ecs.getIp() + ":" + port;
                addresss.add(addr);
                item.setAddress(addr);
            }
        });
        if (CollectionUtil.isEmpty(addresss)) {
            LambdaQueryWrapper<OpenlookengClusterConfig> queryWra = new LambdaQueryWrapper<>();
            queryWra.eq(OpenlookengClusterConfig::getClusterCode, currentLoginUser.getId());
            queryWra.eq(OpenlookengClusterConfig::getProKeyName, Constant.DISCOVERY_URI.getCode());
            List<OpenlookengClusterConfig> uriList = configService.list(queryWra);
            addresss.addAll(uriList.stream().map(item -> item.getProValue()).distinct().collect(Collectors.toList()));
        }
        Map<String, ClusterStateVO> map = this.getMap(addresss);
        records.forEach(a -> {
            a.setNewVersion(newVersion);
            String nodeType = a.getNodeType();
            NodeTypeEnum nodeTypeEnum = NodeTypeEnum.ALL.getNodeTypeEnumByType(nodeType);
            a.setRole(nodeTypeEnum.getRoleName());
            String address = a.getAddress();
            Ecs ecs = ecsList.stream().filter(t -> t.getId().equals(a.getEcsId())).findFirst().get();
            //Coordination node
            if (!Constant.NODE_TYPE_4.getCode().equalsIgnoreCase(a.getNodeType()) && !Constant.NODE_TYPE_1.getCode().equalsIgnoreCase(a.getNodeType())) {
                try {
                    HttpUtil.get(address, 5000);
                    a.setState(Constant.NODE_STATE_ACTIVE.getCode());
                }
                catch (Exception e) {
                    a.setState(Constant.NODE_STATE_SHUTTING_DOWN.getCode());
                }
            }
            else { //Work node
                ClusterStateVO stateVO = map.get(ecs.getIp());
                a.setState(Constant.NODE_STATE_SHUTTING_DOWN.getCode());
                if (ObjectUtil.isNotEmpty(stateVO)) {
                    a.setState(Constant.NODE_STATE_ACTIVE.getCode().equalsIgnoreCase(stateVO.getState()) ? Constant.NODE_STATE_ACTIVE.getCode() : Constant.NODE_STATE_SHUTTING_DOWN.getCode());
                }
            }
            a.setEcs(ecs);
        });
        return page;
    }

    private String parseUrl(String ip, Integer port, String suffix)
    {
        return Constant.HTTP_PREFIX.getCode() + ip + ":" + port + suffix;
    }

    @Override
    public List<OpenlookengCluster> listClusterByCode(String code)
    {
        LambdaQueryWrapper<OpenlookengCluster> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OpenlookengCluster::getClusterCode, code);
        return this.list(queryWrapper);
    }

    @Override
    public List<OpenlookengCluster> listCurrentUserCluster()
    {
        LoginUserInfoDTO loginUserInfoDTO = JwtTokenUtil.getCurrentLoginUser(audience);
        LambdaQueryWrapper<OpenlookengCluster> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OpenlookengCluster::getCreateUserId, loginUserInfoDTO.getId());
        return this.list(queryWrapper);
    }

    @Override
    public List<OpenlookengCluster> listClusterNoPage(OpenlookengClusterQO qo)
    {
        LambdaQueryWrapper<OpenlookengCluster> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotEmpty(qo.getClusterCode())) {
            queryWrapper.eq(OpenlookengCluster::getClusterCode, qo.getClusterCode());
        }
        if (StrUtil.isNotEmpty(qo.getName())) {
            queryWrapper.eq(OpenlookengCluster::getName, qo.getName());
        }
        if (StrUtil.isNotEmpty(qo.getNodeType())) {
            queryWrapper.eq(OpenlookengCluster::getNodeType, qo.getNodeType());
        }
        if (null != qo.getEcsId()) {
            queryWrapper.eq(OpenlookengCluster::getEcsId, qo.getEcsId());
        }
        if (null != qo.getPort()) {
            queryWrapper.eq(OpenlookengCluster::getPort, qo.getPort());
        }
        if (StrUtil.isNotEmpty(qo.getWebUrl())) {
            queryWrapper.eq(OpenlookengCluster::getWebUrl, qo.getWebUrl());
        }
        List<OpenlookengCluster> clusters = baseMapper.selectList(queryWrapper);
        return clusters;
    }

    @Override
    public void updateCluster(AddClusterDTO dto)
    {
        LoginUserInfoDTO currentLoginUser = JwtTokenUtil.getCurrentLoginUser(audience);
        SysFile sysFile = iFileService.getById(dto.getFileId());
        String version = sysFile.getVersion();
        //Add default configuration
        List<OpenlookengClusterConfig> clusterConfigList = configService.listSysDefaultConfig(version);
        if (clusterConfigList.isEmpty()) {
            throw new BizException(version + "版本没有默认配置项,请更换版本!");
        }
        List<OpenlookengCluster> openlookengClusterList = this.listCurrentUserCluster();
        //Insert the configuration of the entire cluster
        clusterConfigList.forEach(a -> {
            a.setId(null);
            a.setCreateUserId(Integer.valueOf(currentLoginUser.getId()));
            a.setClusterCode(currentLoginUser.getId());
            a.setOpenlookengClusterId(-1);
        });
        configService.saveBatch(clusterConfigList);
        //Insert configuration for each node
        List<OpenlookengClusterConfig> finalClusterConfigList = clusterConfigList;
        openlookengClusterList.forEach(b -> {
            finalClusterConfigList.forEach(a -> {
                a.setId(null);
                a.setCreateUserId(Integer.valueOf(currentLoginUser.getId()));
                a.setClusterCode(currentLoginUser.getId());
                a.setOpenlookengClusterId(b.getId());
            });
            configService.saveBatch(finalClusterConfigList);
        });
    }

    @Override
    public void insertCluster(AddClusterDTO dto)
    {
        String[] clusterCode = new String[1];
        String[] nam = new String[1];
        Integer type = dto.getType();
        String code = dto.getCode();
        String name = dto.getName().toLowerCase();
        String installationPath = dto.getInstallationPath();
        String updateWay = dto.getUpgradeWay();
        String url = dto.getWebUrl();
        SysFile byId = iFileService.getById(dto.getFileId());
        String version = null;
        if (ObjectUtil.isNotEmpty(byId)) {
            version = byId.getVersion();
        }
        List<OpenlookengClusterDTO> dtos = dto.getDtos();
        LoginUserInfoDTO currentLoginUser = JwtTokenUtil.getCurrentLoginUser(audience);
        if (CollectionUtil.isEmpty(dtos)) {
            throw new BizException("请添加主机等信息!");
        }
        if (type == 1) {
            if (StrUtil.isEmpty(name)) {
                throw new BizException("集群名称不能为空");
            }
            if (StrUtil.isEmpty(updateWay)) {
                throw new BizException("升级方式不能为空");
            }
            if (StrUtil.isEmpty(version)) {
                throw new BizException("请选择您的安装包!");
            }
            //if (StrUtil.isEmpty(installationPath)) throw new BizException("安装地址不能为空");
            clusterCode[0] = currentLoginUser.getId();
            nam[0] = name;
        }
        else {
            if (StrUtil.isEmpty(code)) {
                throw new BizException("编码不能为空!");
            }
            List<OpenlookengCluster> openlookengClusters = this.listClusterByCode(code);
            if (CollectionUtil.isEmpty(openlookengClusters)) {
                throw new BizException("集群不存在!");
            }
            clusterCode[0] = code;
            nam[0] = openlookengClusters.get(0).getName();
        }
        List<OpenlookengCluster> list = new ArrayList<>();
        String finalVersion = version;
        List<OpenlookengCluster> clusters = baseMapper.selectList(null);
        dtos.forEach(item -> {
            OpenlookengCluster subCluster = new OpenlookengCluster();

            subCluster.setVersion(finalVersion)
                    .setClusterCode(clusterCode[0])
                    .setNodeType(item.getNodeType())
                    .setPort(item.getPort())
                    .setEcsId(item.getEcsId())
                    .setCreateUserId(Integer.parseInt(currentLoginUser.getId()))
                    .setName(nam[0])
                    .setWebUrl(url)
                    .setInstallWay(updateWay)
                    .setInstallationPath(installationPath);
            OpenlookengCluster cluster = clusters.stream().filter(ite -> ite.getEcsId().intValue() == item.getEcsId().intValue()).findFirst().orElse(null);
            if (ObjectUtil.isNotEmpty(cluster)) {
                subCluster.setId(cluster.getId());
            }
            list.add(subCluster);
        });
        this.saveOrUpdateBatch(list);
        List<OpenlookengCluster> listFind = listCurrentUserCluster();
        OpenlookengClusterQO qo = new OpenlookengClusterQO();
        qo.setClusterCode(clusterCode[0]);
        List<OpenlookengCluster> clusterList = this.listClusterNoPage(qo);
        List<OpenlookengCluster> noworkeNodes = clusterList.stream().filter(item -> !Constant.NODE_TYPE_1.getCode().equals(item.getNodeType())).collect(Collectors.toList());
        List<OpenlookengCluster> works = listFind.stream().filter(item -> !Constant.NODE_TYPE_1.getCode().equals(item.getNodeType())).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(noworkeNodes) && CollectionUtil.isEmpty(works)) {
            throw new BizException("请至少设置一个协调节点!");
        }
        clusterList.forEach(item -> {
            long count = listFind.stream().filter(ite -> ite.getId().equals(item.getId())).count();
            if (count == 0) {
                throw new BizException("当前用户已经创建集群,无法再次创建!");
            }
        });

        configService.deleteClusterConfig();
        List<OpenlookengClusterConfig> clusterConfigList = configService.listSysDefaultConfig(version);
        if (clusterConfigList.isEmpty()) {
            throw new BizException(version + "版本没有默认配置项,请更换版本!");
        }
        clusterConfigList = clusterConfigList.stream().filter(a -> {
            return ConfigTypeEnum.NODE.getTypeGroup().equalsIgnoreCase(a.getTypeGroup());
        }).collect(Collectors.toList());
        clusterConfigList.forEach(a -> {
            a.setId(null);
            a.setCreateUserId(Integer.valueOf(currentLoginUser.getId()));
            a.setClusterCode(currentLoginUser.getId());
            a.setOpenlookengClusterId(-1);
        });
        configService.saveBatch(clusterConfigList);
        List<OpenlookengClusterConfig> finalClusterConfigList = clusterConfigList;
        listFind.forEach(b -> {
            finalClusterConfigList.forEach(a -> {
                a.setId(null);
                a.setCreateUserId(Integer.valueOf(currentLoginUser.getId()));
                a.setClusterCode(currentLoginUser.getId());
                a.setOpenlookengClusterId(b.getId());
            });
            configService.saveBatch(finalClusterConfigList);
        });
    }

    @Override
    public String addNode(AddClusterDTO dto)
    {
        LoginUserInfoDTO userInfoDTO = JwtTokenUtil.getCurrentLoginUser(audience);
        String updateWay = dto.getUpgradeWay();
        String fileId = dto.getFileId();
        if (StringUtils.isBlank(fileId)) {
            throw new BizException("请选择您的安装包!");
        }
        if (StrUtil.isEmpty(updateWay)) {
            throw new BizException("升级方式不能为空");
        }
        SysFile sysFile = iFileService.getById(fileId);
        String version = sysFile.getVersion();

        List<OpenlookengClusterConfig> clusterConfigList = configService.listClusterConfig(Integer.valueOf(userInfoDTO.getId()), -1, version);
        if (clusterConfigList.isEmpty()) {
            throw new BizException(version + "版本没有默认配置项,请更换版本!");
        }
        List<OpenlookengClusterDTO> openlookengClusterDTOList = dto.getDtos();
        List<OpenlookengCluster> openlookengClusterList = openlookengClusterDTOList.stream().map(a -> {
            OpenlookengCluster openlookengCluster = new OpenlookengCluster();
            BeanUtil.copyProperties(a, openlookengCluster);
            openlookengCluster.setConfigSynState(ConfigSynStateEnum.UN_SYN.getType());
            openlookengCluster.setVersion(version);
            openlookengCluster.setClusterCode(userInfoDTO.getId());
            openlookengCluster.setInstallWay(updateWay);
            openlookengCluster.setCreateUserId(Integer.valueOf(userInfoDTO.getId()));
            openlookengCluster.setInstallationPath(dto.getInstallationPath());
            return openlookengCluster;
        }).collect(Collectors.toList());
        this.saveBatch(openlookengClusterList);
        List<Integer> ecsIdList = openlookengClusterList.stream().map(a -> a.getEcsId()).distinct().collect(Collectors.toList());
        openlookengClusterList = this.listClusterByEcsIds(ecsIdList);
        openlookengClusterList.forEach(a -> {
            List<OpenlookengClusterConfig> nodeConfig = clusterConfigList.stream().map(t -> {
                OpenlookengClusterConfig config = new OpenlookengClusterConfig();
                BeanUtil.copyProperties(t, config);
                config.setOpenlookengClusterId(a.getId());
                return config;
            }).collect(Collectors.toList());
            configService.saveBatch(nodeConfig);
        });
        List<Integer> escIdList = openlookengClusterList.stream().map(a -> a.getEcsId()).distinct().collect(Collectors.toList());
        List<Ecs> ecsList = iEcsService.listByIds(escIdList);
        openLookengService.deployNodeList(Integer.valueOf(dto.getFileId()), openlookengClusterList, ecsList, dto.getIsStart());

        LambdaQueryWrapper<OpenlookengCluster> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OpenlookengCluster::getClusterCode, userInfoDTO.getId());
        queryWrapper.ne(OpenlookengCluster::getNodeType, Constant.NODE_TYPE_1.getCode());
        List<OpenlookengCluster> list = this.list(queryWrapper);
        if (list.size() > 1) {
            return "操作成功,如需开启ha,请配置文件系统和状态存储";
        }
        else {
            return "操作成功";
        }
    }

    public List<OpenlookengCluster> listClusterByEcsIds(List<Integer> ecsIdList)
    {
        LambdaQueryWrapper<OpenlookengCluster> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(OpenlookengCluster::getEcsId, ecsIdList);
        return this.list(wrapper);
    }

    @Override
    public void deleteCluster(List<String> code)
    {
        LambdaQueryWrapper<OpenlookengCluster> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(OpenlookengCluster::getClusterCode, code);
        baseMapper.delete(wrapper);
    }

    public Map<String, ClusterStateVO> queryState(String url)
    {
        Map<String, ClusterStateVO> map = new HashMap<>();
        try {
            String msg = HttpUtil.get(url, 1000);
            JSONObject jsonObject = JSONUtil.parseObj(msg);
            for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                JSONObject obj = JSONUtil.parseObj(value);
                ClusterStateVO clusterStateVO = JSONUtil.toBean(value.toString(), ClusterStateVO.class);
                JSONObject poolObject = JSONUtil.parseObj(obj.get("pools"));
                if (ObjectUtil.isNotEmpty(poolObject)) {
                    ClusterStateGeneralVO generalVO = JSONUtil.toBean(poolObject.get("general").toString(), ClusterStateGeneralVO.class);
                    clusterStateVO.setPools(generalVO);
                }
                map.put(key, clusterStateVO);
            }
        }
        catch (Exception e) {
            return map;
        }
        return map;
    }

    @Override
    public Map<String, String> queryClusterItem(String code)
    {
        OpenlookengClusterQO qo = new OpenlookengClusterQO();
        qo.setClusterCode(code);
        List<OpenlookengCluster> clusters = this.listClusterNoPage(qo);
        if (CollectionUtil.isEmpty(clusters)) {
            throw new BizException("集群不存在!");
        }
        return this.getClusterAttr(clusters);
    }

    @Override
    public Map<String, String> queryTotalCluster()
    {
        Map<String, String> map = new HashMap<>();
        try {
            List<Ecs> ecsList = iEcsService.listByUserId();
            map.put("serverNum", ecsList.size() + "");
            List<OpenlookengCluster> clusterList = this.listCurrentUserCluster();
            if (clusterList.isEmpty()) {
                map.put("clusterNum", clusterList.size() + "");
                return map;
            }
            List<String> clusterCodeList = clusterList.stream().map(a -> a.getClusterCode()).distinct().collect(Collectors.toList());
            List<String> versionList = clusterList.stream().map(a -> a.getVersion()).distinct().collect(Collectors.toList());
            map.put("clusterNum", clusterCodeList.size() + "");
            if (clusterCodeList.isEmpty()) {
                map.put("clusterState", "notInstall");
            }
            else {
                ClusterChartInfoDTO clusterChartInfoDTO = this.getClusterChartInfoDTO(clusterCodeList.get(0), versionList.get(0));
                if (clusterChartInfoDTO == null) {
                    map.put("clusterState", "closed");
                }
                else {
                    map.put("clusterState", "running");
                }
            }
            Long coordinatorNum = clusterList.stream().filter(a -> {
                return NodeTypeEnum.ALL.getType().equalsIgnoreCase(a.getNodeType()) || NodeTypeEnum.COORDINATOR.getType().equalsIgnoreCase(a.getNodeType());
            }).count();

            Long workerNum = clusterList.stream().filter(a -> {
                return NodeTypeEnum.ALL.getType().equalsIgnoreCase(a.getNodeType()) || NodeTypeEnum.WORKER_NODES.getType().equalsIgnoreCase(a.getNodeType());
            }).count();
            map.put("coordinatorNum", coordinatorNum.toString());
            map.put("workerNum", workerNum.toString());
            BigDecimal memTotal = BigDecimal.ZERO;
            BigDecimal memSysUsed = BigDecimal.ZERO;
            BigDecimal cpuTotalNum = BigDecimal.ZERO;
            BigDecimal cpuUsedNum = BigDecimal.ZERO;
            List<Map<String, String>> resList = ecsList.stream().map(a -> {
                return iEcsService.getOsInfoFromCache(a);
            }).collect(Collectors.toList());
            for (Map<String, String> res : resList) {
                String cpuNum = res.getOrDefault("cpu_num", "0");
                String cpuUser = res.getOrDefault("cpu_user", "0");
                BigDecimal cpuNumVal = new BigDecimal(cpuNum);
                BigDecimal cpuUserVal = cpuNumVal.multiply(new BigDecimal(cpuUser)).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP);
                String memTotalStr = res.getOrDefault("mem_total", "0");
                Double memTotalVal = kbToGb(memTotalStr);
                String memSysUsedStr = res.getOrDefault("mem_sys_used", "0");
                Double memSysUsedVal = kbToGb(memSysUsedStr);
                memTotal = memTotal.add(BigDecimal.valueOf(memTotalVal));
                memSysUsed = memSysUsed.add(BigDecimal.valueOf(memSysUsedVal));
                cpuTotalNum = cpuTotalNum.add(cpuNumVal);
                cpuUsedNum = cpuUsedNum.add(cpuUserVal);
            }
            map.put("memSysUsed", memSysUsed.toString());
            map.put("memTotal", memTotal.toString());
            map.put("cpuUsedNum", cpuUsedNum.toString());
            map.put("cpuTotalNum", cpuTotalNum.toString());
        }
        catch (Exception e) {
            return map;
        }
        return map;
    }

    @Override
    public HostStatusAndTypeQo getHostStatusAndType()
    {
        LoginUserInfoDTO loginUserInfoDTO = JwtTokenUtil.getCurrentLoginUser(audience);
        LambdaQueryWrapper<OpenlookengCluster> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OpenlookengCluster::getClusterCode, loginUserInfoDTO.getId());
        List<OpenlookengCluster> openlookengClusters = this.baseMapper.selectList(wrapper);
        HostStatusAndTypeQo hostStatusAndTypeQo = new HostStatusAndTypeQo();
        if (openlookengClusters.isEmpty()) {
            return hostStatusAndTypeQo;
        }
        else {
            List<OpenlookengClusterVO> clusterVOS = new ArrayList<>();
            openlookengClusters.forEach(item -> {
                OpenlookengClusterVO vo = new OpenlookengClusterVO();
                BeanUtil.copyProperties(item, vo);
                clusterVOS.add(vo);
            });
            List<Ecs> ecsList = iEcsService.list(null);
            LambdaQueryWrapper<OpenlookengClusterConfig> configQueryWrapper = new LambdaQueryWrapper<>();
            configQueryWrapper.eq(OpenlookengClusterConfig::getClusterCode, loginUserInfoDTO.getId());
            List<OpenlookengClusterConfig> configs = configService.list(configQueryWrapper);

            List<String> addres = new ArrayList<>();
            clusterVOS.forEach(item -> {
                Ecs ecs = ecsList.stream().filter(it -> item.getEcsId().equals(it.getId())).findFirst().orElse(null);
                if (ObjectUtil.isNotEmpty(ecs)) {
                    item.setEcs(ecs);
                    List<OpenlookengClusterConfig> collect = configs.stream().filter(it -> item.getId().equals(it.getOpenlookengClusterId()) && item.getVersion().equalsIgnoreCase(it.getVersion())).collect(Collectors.toList());
                    if (!Constant.NODE_TYPE_4.getCode().equalsIgnoreCase(item.getNodeType()) && !Constant.NODE_TYPE_1.getCode().equalsIgnoreCase(item.getNodeType())) {
                        OpenlookengClusterConfig config = collect.stream().filter(it -> Constant.HTTP_SERVER_HTTP_PORT.getCode().equalsIgnoreCase(it.getProKeyName())).findFirst().orElse(null);
                        if (ObjectUtil.isNotEmpty(config)) {
                            item.setAddress(ecs.getIp() + ":" + config.getProValue());
                            addres.add(ecs.getIp() + ":" + config.getProValue());
                        }
                    }
                }
            });
            Map<String, ClusterStateVO> map = this.getMap(addres);

            clusterVOS.forEach(item -> {
                if (Constant.NODE_TYPE_4.getCode().equalsIgnoreCase(item.getNodeType()) || Constant.NODE_TYPE_1.getCode().equalsIgnoreCase(item.getNodeType())) {
                    if (CollectionUtil.isNotEmpty(map)) {
                        if (ObjectUtil.isNotEmpty(item.getEcs())) {
                            ClusterStateVO stateVO = map.get(item.getEcs().getIp());
                            if (ObjectUtil.isNotEmpty(stateVO)) {
                                if (Constant.NODE_STATE_ACTIVE.getCode().equalsIgnoreCase(stateVO.getState())) {
                                    hostStatusAndTypeQo.setSurvivalRate(hostStatusAndTypeQo.getSurvivalRate() + 1);
                                }
                            }
                        }
                    }
                }
                else {
                    try {
                        HttpUtil.get(item.getAddress(), 5000);
                        if (Constant.NODE_TYPE_2.getCode().equalsIgnoreCase(item.getNodeType())) {
                            hostStatusAndTypeQo.setSurvivalRate(hostStatusAndTypeQo.getSurvivalRate() + 1);
                        }
                        else {
                            hostStatusAndTypeQo.setSurvivalRate(hostStatusAndTypeQo.getSurvivalRate() + 2);
                        }
                    }
                    catch (Exception e) {
                    }
                }
            });
            Long workerNum = openlookengClusters.stream().filter(i -> i.getNodeType().equalsIgnoreCase(Constant.NODE_TYPE_0.getCode()) || i.getNodeType().equalsIgnoreCase(Constant.NODE_TYPE_1.getCode())).count();
            Long coordinatorNum = openlookengClusters.stream().filter(i -> i.getNodeType().equalsIgnoreCase(Constant.NODE_TYPE_0.getCode()) || i.getNodeType().equalsIgnoreCase(Constant.NODE_TYPE_2.getCode())).count();
            hostStatusAndTypeQo.setWorker(workerNum);
            hostStatusAndTypeQo.setCoordinator(coordinatorNum);
            hostStatusAndTypeQo.setTotal(workerNum.intValue() + coordinatorNum.intValue());
            return hostStatusAndTypeQo;
        }
    }

    private Map<String, String> getClusterAttr(List<OpenlookengCluster> list)
    {
        Map<String, String> map = new HashMap<>();
        try {
            List<Ecs> ecss = iEcsService.listByUserId();
            list.forEach(item -> {
                if (StrUtil.isEmpty(item.getWebUrl())) {
                    Ecs ecs = ecss.stream().filter(ecsItem -> ecsItem.getId() == (long) item.getEcsId()).findFirst().orElse(null);
                    if (ObjectUtil.isNotEmpty(ecs)) {
                        String ip = ecs.getIp();
                        item.setWebUrl(parseUrl(ip, item.getPort(), Constant.URL_STATE_SUFFIX.getCode()));
                    }
                }
            });
            Map<String, ClusterStateVO> totalMap = new HashMap<>();
            List<String> urls = list.stream().map(item -> item.getWebUrl()).distinct().collect(Collectors.toList());
            urls.forEach(item -> {
                Map<String, ClusterStateVO> stateMap = this.queryState(item);
                if (CollectionUtil.isNotEmpty(stateMap)) {
                    totalMap.putAll(stateMap);
                }
            });
            long runNodeNum = totalMap.values().stream().filter(item -> Constant.NODE_STATE_ACTIVE.getCode().equalsIgnoreCase(item.getState())).count();
            long closeNodeNum = totalMap.values().stream().filter(item -> Constant.NODE_STATE_SHUTTING_DOWN.getCode().equalsIgnoreCase(item.getState())).count();

            Map<String, ClusterStateVO> keyIpMap = new HashMap<>();
            for (String s : totalMap.keySet()) {
                String[] split = s.split(Constant.HTTP_PREFIX.getCode());
                if (split.length > 1) {
                    int i1 = split[1].lastIndexOf(":");
                    String ip = split[1].substring(0, i1);
                    keyIpMap.put(ip, totalMap.get(s));
                }
            }

            Double[] ram = new Double[1];
            ram[0] = 0d;
            Double[] totalRam = new Double[1];
            totalRam[0] = 0d;
            int[] cpu = new int[1];
            cpu[0] = 0;
            int[] totalCpu = new int[1];
            totalCpu[0] = 0;
            keyIpMap.forEach((k, v) -> {
                ram[0] += ram[0] + getTotalNodeMemory(v.getTotalNodeMemory()); //   Long.parseLong(v.getTotalNodeMemory());
                cpu[0] += cpu[0] + v.getProcessCpuLoad();
                totalCpu[0] += totalCpu[0] + v.getSystemCpuLoad();
            });
            map.put("ram", ram[0] + "");
            map.put("totalRam", totalRam[0] + "");
            map.put("cpu", cpu[0] + "");
            map.put("totalCpu", totalCpu[0] + "");
            map.put("runNodeNum", runNodeNum + "");
            map.put("closeNodeNum", closeNodeNum + "");
            map.put("clusterName", list.get(0).getName());
            map.put("address", "");
        }
        catch (Exception e) {
            return map;
        }
        return map;
    }

    public Double kbToGb(String totalMemory)
    {
        if (StringUtils.isBlank(totalMemory)) {
            return 0d;
        }
        BigDecimal devideNum = BigDecimal.valueOf(1048576L);
        BigDecimal res = BigDecimal.valueOf(Long.valueOf(totalMemory)).divide(devideNum, 2, BigDecimal.ROUND_UP);
        return res.doubleValue();
    }

    /**
     * @return
     */
    public Double getTotalNodeMemory(String totalNodeMemory)
    {
        if (StringUtils.isBlank(totalNodeMemory)) {
            return 0d;
        }
        BigDecimal devideNum = BigDecimal.valueOf(1073741824L);
        totalNodeMemory = totalNodeMemory.replaceAll("B", "");
        BigDecimal res = BigDecimal.valueOf(Long.valueOf(totalNodeMemory)).divide(devideNum, 2, BigDecimal.ROUND_UP);
        return res.doubleValue();
    }

    /**
     * Get chart data of a cluster
     *
     * @param clusterCode
     * @return
     */
    public ClusterChartInfoDTO getClusterChartInfoDTO(String clusterCode, String version)
    {
        String webUrl = getWebUrl(clusterCode, version);
        String apiUrl = webUrl + Constant.CLUSTER_CHART_IFNO.getCode();
        try {
            String jsonStr = HttpUtil.get(apiUrl, 1000);
            Boolean isJson = JSONUtil.isJson(jsonStr);
            if (isJson) {
                ClusterChartInfoDTO clusterChartInfoDTO = JSONUtil.toBean(jsonStr, ClusterChartInfoDTO.class);
                return clusterChartInfoDTO;
            }
            else {
                return null;
            }
        }
        catch (Exception e) {
            return null;
        }
    }

    public String getWebUrl(String clusterCode, String version)
    {
        List<String> urlList = configService.listDiscoveryUri(clusterCode, version);
        if (!urlList.isEmpty()) {
            return urlList.get(0);
        }
        return null;
    }

    public String getWebUrl(Integer nodeId, String version)
    {
        List<String> urlList = configService.listDiscoveryUri(nodeId, version);
        if (!urlList.isEmpty()) {
            return urlList.get(0);
        }
        return null;
    }

    @Override
    public ClusterItemVO queryClusterItemV2(String code)
    {
        ClusterItemVO itemVO = new ClusterItemVO();
        OpenlookengClusterQO qo = new OpenlookengClusterQO();
        qo.setClusterCode(code);
        List<OpenlookengCluster> clustersPO = this.listClusterNoPage(qo);
        List<OpenlookengClusterVO> clusters = new ArrayList<>();
        clustersPO.forEach(item -> {
            OpenlookengClusterVO vo = new OpenlookengClusterVO();
            BeanUtil.copyProperties(item, vo);
            clusters.add(vo);
        });
        if (CollectionUtil.isEmpty(clusters)) {
            return itemVO;
        }

        List<String> vers = clusters.stream().map(item -> item.getVersion()).distinct().collect(Collectors.toList());
        Long aLong = vers.stream().map(item -> Long.parseLong(String.join("", item.split("\\.")))).sorted().findFirst().get();

        for (OpenlookengCluster cluster : clusters) {
            long l = Long.parseLong(String.join("", cluster.getVersion().split("\\.")));
            if (aLong.equals(l)) {
                itemVO.setClusterVer(cluster.getVersion());
                break;
            }
        }
        //Coordination node ID
        List<Integer> coorNodes = clusters.stream().filter(item -> !Constant.NODE_TYPE_1.getCode().equalsIgnoreCase(item.getNodeType())).map(item -> item.getId()).distinct().collect(Collectors.toList());

        //Query the configuration according to the code and node ID
        List<Integer> clusterIds = clusters.stream().map(item -> item.getId()).distinct().collect(Collectors.toList());
        LambdaQueryWrapper<OpenlookengClusterConfig> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OpenlookengClusterConfig::getClusterCode, code);
        List<OpenlookengClusterConfig> clusterConfigList = configService.list(queryWrapper);
        List<OpenlookengClusterConfig> clusterConfigs = clusterConfigList.stream()
                .filter(item -> Constant.HTTP_SERVER_HTTP_PORT.getCode().equalsIgnoreCase(item.getProKeyName())
                        && clusterIds.contains(item.getOpenlookengClusterId())).collect(Collectors.toList());

        List<String> noWorkNodeAddr = clusterConfigList.stream().filter(item -> coorNodes.contains(item.getOpenlookengClusterId())
                && Constant.DISCOVERY_URI.getCode().equalsIgnoreCase(item.getProKeyName())
                && item.getVersion().equals(itemVO.getClusterVer())).map(item -> item.getProValue()).distinct().collect(Collectors.toList());
        itemVO.setAddress(noWorkNodeAddr); //Access address

        //Query all hosts
        List<Ecs> ecsList = iEcsService.list(null);
        clusters.forEach(item -> {
            Ecs ecs = ecsList.stream().filter(ite -> item.getEcsId().equals(ite.getId())).findFirst().orElse(null);
            item.setEcs(ecs);
            OpenlookengClusterConfig config = clusterConfigs.stream().filter(ite -> ite.getVersion().equalsIgnoreCase(item.getVersion()) && item.getId().equals(ite.getOpenlookengClusterId())).findFirst().orElse(null);
            if (ObjectUtil.isNotEmpty(ecs) && ObjectUtil.isNotEmpty(config)) {
                String ip = ecs.getIp();
                String port = config.getProValue();
                String address = Constant.HTTP_PREFIX.getCode() + ip + ":" + port;
                item.setAddress(address);
                item.setServerIp(ip);
                item.setServerPort(ecs.getPort());
                item.setServerUserName(ecs.getUserName());
                item.setServerPwd(Md5Utils.decrypt(ecs.getPassWord()));
            }
        });
        //Filter out coordination nodes
        List<String> addressList = clusters.stream().filter(item -> !Constant.NODE_TYPE_1.getCode().equalsIgnoreCase(item.getNodeType())).map(item -> item.getAddress()).distinct().collect(Collectors.toList());
        Map<String, ClusterStateVO> clusterItemMap = this.getMap(addressList);

        Map<String, Map<String, Long>> nodeItemMap = new HashMap<>();

        clusters.forEach(item -> {
            if (Constant.NODE_TYPE_1.getCode().equalsIgnoreCase(item.getNodeType())) {
                item.setNodeType(Constant.NODE_TYPE_4.getCode());
            }
            if (Constant.NODE_TYPE_0.getCode().equalsIgnoreCase(item.getNodeType())) {
                item.setNodeType(Constant.NODE_TYPE_3.getCode());
            }
        });

        clusters.forEach(item -> {
            Map<String, Long> stateMap = new HashMap<>();
            stateMap.put(Constant.NODE_STATE_ACTIVE.getMsg(), 0L);
            stateMap.put(Constant.NODE_STATE_SHUTTING_DOWN.getMsg(), 0L);
            Map<String, Long> map = nodeItemMap.get(item.getNodeType());
            if (CollectionUtil.isNotEmpty(map)) {
                stateMap = map;
            }
            if (!Constant.NODE_TYPE_2.getCode().equalsIgnoreCase(item.getNodeType())) {
                Ecs ecs = item.getEcs();
                if (ObjectUtil.isNotEmpty(ecs)) {
                    ClusterStateVO stateVO = clusterItemMap.get(ecs.getIp());
                    if (ObjectUtil.isNotEmpty(stateVO)) {
                        String state = stateVO.getState();
                        if (Constant.NODE_STATE_ACTIVE.getCode().equalsIgnoreCase(state)) {
                            Long runNum = stateMap.get(Constant.NODE_STATE_ACTIVE.getMsg());
                            stateMap.put(Constant.NODE_STATE_ACTIVE.getMsg(), runNum + 1);
                        }
                        else {
                            Long stopNum = stateMap.get(Constant.NODE_STATE_SHUTTING_DOWN.getMsg());
                            stateMap.put(Constant.NODE_STATE_SHUTTING_DOWN.getMsg(), stopNum + 1);
                        }
                    }
                    else {
                        Long stopNum = stateMap.get(Constant.NODE_STATE_SHUTTING_DOWN.getMsg());
                        stateMap.put(Constant.NODE_STATE_SHUTTING_DOWN.getMsg(), stopNum + 1);
                    }
                }
            }
            else {
                try {
                    HttpUtil.get(item.getAddress() + Constant.URL_STATE_SUFFIX.getCode(), 5000);
                    Long runNum = stateMap.get(Constant.NODE_STATE_ACTIVE.getMsg());
                    stateMap.put(Constant.NODE_STATE_ACTIVE.getMsg(), runNum + 1);
                }
                catch (Exception e) {
                    Long stopNum = stateMap.get(Constant.NODE_STATE_SHUTTING_DOWN.getMsg());
                    stateMap.put(Constant.NODE_STATE_SHUTTING_DOWN.getMsg(), stopNum + 1);
                }
            }
            nodeItemMap.put(item.getNodeType(), stateMap);
        });
        itemVO.setNodeItem(nodeItemMap);

        Map<String, List<ClusterStateVO>> clusterRoleItemMap = new HashMap<>();
        Long[] totalRam = new Long[]{0L};
        Long[] userRam = new Long[]{0L};
        Double[] useCpu = new Double[]{0d};
        Double[] totalCpu = new Double[]{0d};
        clusterItemMap.forEach((k, v) -> {
            totalCpu[0] += v.getAvailableProcessors();
            if (null != v.getPools()) {
                totalRam[0] += (null != v.getPools().getMaxBytes() ? v.getPools().getMaxBytes() : 0);
                userRam[0] += ((null != v.getPools().getMaxBytes() ? v.getPools().getMaxBytes() : 0) - (null != v.getPools().getFreeBytes() ? v.getPools().getFreeBytes() : 0));
            }
            useCpu[0] += v.getProcessCpuLoad() * v.getAvailableProcessors();
            List<ClusterStateVO> value = clusterRoleItemMap.get(v.getRole());
            if (CollectionUtil.isEmpty(value)) {
                List<ClusterStateVO> valueList = new ArrayList<>();
                valueList.add(v);
                clusterRoleItemMap.put(v.getRole(), valueList);
            }
            else {
                value.add(v);
            }
        });
        nodeItemMap.values().stream().forEach(item -> {
            itemVO.setNodeRunNum(itemVO.getNodeRunNum() + item.get(Constant.NODE_STATE_ACTIVE.getMsg()));
            itemVO.setNodecloseNum(itemVO.getNodecloseNum() + item.get(Constant.NODE_STATE_SHUTTING_DOWN.getMsg()));
        });
        itemVO.setClusterName(clusters.get(0).getName());

        List<OpenlookengClusterVO> coorNode = clusters.stream().filter(item -> Constant.NODE_TYPE_2.getCode().equalsIgnoreCase(item.getNodeType())).collect(Collectors.toList());
        coorNode.forEach(item -> {
            SshUserDTO sshUserDTO = new SshUserDTO();
            sshUserDTO.setSshUser(item.getServerUserName());
            sshUserDTO.setSshPass(item.getServerPwd());
            sshUserDTO.setSshHost(item.getServerIp());
            sshUserDTO.setSshPort(item.getServerPort());
            Map<String, String> osInfo = iEcsService.getOsInfoFromCache(item.getEcs());
            if (CollectionUtil.isNotEmpty(osInfo) && osInfo.size() > 1) {
                String cpuNum = osInfo.getOrDefault("cpu_num", "0"); //cpu总核数
                String cpuUser = osInfo.getOrDefault("cpu_user", "0"); //cpu空闲
                String memTotal = osInfo.getOrDefault("mem_total", "0"); //内存总量
                String memSysUsed = osInfo.getOrDefault("mem_sys_used", "0"); //操作系统已使用内存总量
                if (StrUtil.isBlank(cpuNum)) {
                    cpuNum = "0";
                }
                if (StrUtil.isBlank(cpuUser)) {
                    cpuUser = "0";
                }
                if (StrUtil.isBlank(memTotal)) {
                    memTotal = "0";
                }
                if (StrUtil.isBlank(memSysUsed)) {
                    memSysUsed = "0";
                }
                totalCpu[0] += Double.parseDouble(cpuNum);
                useCpu[0] += (Double.parseDouble(cpuUser) / 100 * Double.parseDouble(cpuNum));
                totalRam[0] += Long.parseLong(memTotal);
                userRam[0] += Long.parseLong(memSysUsed);
            }
        });
        itemVO.setTotalCpu(totalCpu[0]);
        itemVO.setUseCpu(Double.valueOf(String.format("%.2f", useCpu[0])));
        itemVO.setTotalRam(this.getTotalNodeMemory(totalRam[0] + ""));
        itemVO.setUseRam(this.getTotalNodeMemory(userRam[0] + ""));
        try {
            Map<String, Object> info = this.info(code, vers.get(0));
            itemVO.setUptime(info.getOrDefault("uptime", "0").toString());
        }
        catch (Exception e) {
            log.info("err:{}", e.getMessage());
        }
        return itemVO;
    }

    @Override
    public Map<String, ClusterStateVO> getMap(List<String> webUrls)
    {
        Map<String, ClusterStateVO> totalMap = new HashMap<>();
        webUrls.stream().distinct().forEach(item -> {
            Map<String, ClusterStateVO> stateMap = queryState(item + Constant.URL_STATE_SUFFIX.getCode());
            if (CollectionUtil.isNotEmpty(stateMap)) {
                for (String s : stateMap.keySet()) {
                    String[] split = s.split(Constant.HTTP_PREFIX.getCode());
                    if (split.length > 1) {
                        int i1 = split[1].lastIndexOf(":");
                        String ip = split[1].substring(0, i1);
                        totalMap.put(ip, stateMap.get(s));
                    }
                }
            }
        });
        return totalMap;
    }

    @Override
    public NodeItemVO queryNodeItemV2(Integer id)
    {
        OpenlookengCluster cluster = baseMapper.selectById(id);
        if (ObjectUtil.isEmpty(cluster)) {
            throw new BizException("实例不存在");
        }
        Ecs ecsObj = iEcsService.getById(cluster.getEcsId());
        if (ObjectUtil.isEmpty(ecsObj)) {
            throw new BizException("主机不存在");
        }
        String ip = ecsObj.getIp();

        LoginUserInfoDTO currentLoginUser = JwtTokenUtil.getCurrentLoginUser(audience);
        LambdaQueryWrapper<OpenlookengClusterConfig> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OpenlookengClusterConfig::getClusterCode, currentLoginUser.getId());
        wrapper.in(OpenlookengClusterConfig::getOpenlookengClusterId, Arrays.asList(cluster.getId()));
        wrapper.eq(OpenlookengClusterConfig::getProKeyName, Constant.HTTP_SERVER_HTTP_PORT.getCode());
        List<OpenlookengClusterConfig> configs = configService.list(wrapper);

        String url = null;
        OpenlookengClusterConfig config = configs.stream().filter(it -> cluster.getVersion().equals(it.getVersion()) && it.getOpenlookengClusterId().equals(cluster.getId())).findFirst().orElse(null);
        if (ObjectUtil.isNotEmpty(config)) {
            url = ecsObj.getIp() + ":" + config.getProValue();
        }

        //Query the logs under the server path
        List<String> list = new ArrayList<>();
        Cache nodeListFileCache = cacheManager.getCache(Constant.NODE_LOG_CACHE.getCode());
        if (ObjectUtil.isNotEmpty(nodeListFileCache)) {
            list = nodeListFileCache.get(Constant.NODE_LOG_CACHE_KEY.getCode() + ecsObj.getId(), List.class);
        }

        NodeItemVO vo = new NodeItemVO();
        vo.setState(Constant.NODE_STATE_ACTIVE.getCode());
        if (!Constant.NODE_TYPE_4.getCode().equalsIgnoreCase(cluster.getNodeType()) && !Constant.NODE_TYPE_1.getCode().equalsIgnoreCase(cluster.getNodeType())) {
            Map<String, String> cache = iEcsService.getOsInfoFromCache(ecsObj);
            if (CollectionUtil.isNotEmpty(cache)) {
                String cpuNum = cache.get("cpu_num");
                String cpuUser = cache.get("cpu_user");
                String memTotal = cache.get("mem_total");
                String memSysUsed = cache.get("mem_sys_used");
                if (StrUtil.isBlank(cpuNum)) {
                    cpuNum = "0";
                }
                if (StrUtil.isBlank(cpuUser)) {
                    cpuUser = "0";
                }
                if (StrUtil.isBlank(memTotal)) {
                    memTotal = "0";
                }
                if (StrUtil.isBlank(memSysUsed)) {
                    memSysUsed = "0";
                }
                vo.setUseCpu(Double.valueOf(String.format("%.2f", (Double.parseDouble(cpuUser) / 100 * Double.parseDouble(cpuNum)))))
                        .setRole(Constant.NODE_TYPE_0.getCode().equalsIgnoreCase(cluster.getNodeType()) ? Constant.NODE_TYPE_3.getCode() : cluster.getNodeType())
                        .setUseRam(this.getTotalNodeMemory(Long.parseLong(memSysUsed) + ""))
                        .setTotalRam(this.getTotalNodeMemory(Long.parseLong(memTotal) + ""))
                        .setTotalCpu(Double.parseDouble(cpuNum));
            }
            try {
                HttpUtil.get(url, 5000);
            }
            catch (Exception e) {
                vo.setState(Constant.NODE_STATE_SHUTTING_DOWN.getCode());
            }
        }
        else {
            Map<String, ClusterStateVO> keyIpMap = this.getMap(Arrays.asList(this.getWebUrl(id, cluster.getVersion())));
            ClusterStateVO stateVO = keyIpMap.get(ip);
            if (ObjectUtil.isNotEmpty(stateVO)) {
                Long maxBytes = stateVO.getPools().getMaxBytes();
                Long freeBytes = stateVO.getPools().getFreeBytes();
                vo.setUseCpu(Double.valueOf(String.format("%.2f", new Double(stateVO.getProcessCpuLoad() * stateVO.getAvailableProcessors()))))
                        .setState(Constant.NODE_STATE_ACTIVE.getCode().equalsIgnoreCase(stateVO.getState()) ? stateVO.getState() : Constant.NODE_STATE_SHUTTING_DOWN.getCode())
                        .setUseRam(this.getTotalNodeMemory(((null != maxBytes ? maxBytes : 0) - (null != freeBytes ? freeBytes : 0)) + ""))
                        .setTotalRam(this.getTotalNodeMemory(stateVO.getTotalNodeMemory()))
                        .setTotalCpu(new Double(stateVO.getAvailableProcessors()));
            }
            else {
                vo.setState(Constant.NODE_STATE_SHUTTING_DOWN.getCode());
            }
        }
        NodeTypeEnum nodeTypeEnumByType = NodeTypeEnum.ALL.getNodeTypeEnumByType(cluster.getNodeType());
        vo.setInstallationPath(cluster.getInstallationPath())
                .setVersion(cluster.getVersion())
                .setLog(list)
                .setEcsId(ecsObj.getId())
                .setRole(Constant.NODE_TYPE_0.getCode().equalsIgnoreCase(cluster.getNodeType()) ? Constant.NODE_TYPE_3.getCode() : nodeTypeEnumByType.getRoleName())
                .setIp(ecsObj.getIp());
        return vo;
    }

    @Override
    public void checkGuide()
    {
        LoginUserInfoDTO currentLoginUser = JwtTokenUtil.getCurrentLoginUser(audience);
        List<OpenlookengCluster> openlookengClusters = this.listClusterByCode(currentLoginUser.getId());
        if (CollectionUtil.isNotEmpty(openlookengClusters)) {
            throw new BizException("当前用户已经创建集群,请勿重复创建");
        }
    }

    public Map<String, Object> info(String clusterCode, String version)
    {
        try {
            String webUrl = getWebUrl(clusterCode, version);
            String jsonStr = HttpUtil.get(webUrl + Constant.URL_VERSION_SUFFIX.getCode(), 1000);
            Map<String, Object> dataMap = JSONUtil.toBean(jsonStr, Map.class);
            return dataMap;
        }
        catch (Exception e) {
            return new HashMap<>();
        }
    }

    @Override
    public void cacheAllClusterInfo()
    {
        List<OpenlookengCluster> clusterList = this.list();
        List<Ecs> ecsList = iEcsService.list();
        Cache cache = cacheManager.getCache("clusterCache");
        List<OpenlookengClusterConfig> allConfigList = new ArrayList<>();

        clusterList.forEach(a -> {
            Integer id = a.getId();
            String version = a.getVersion();
            LambdaQueryWrapper<OpenlookengClusterConfig> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(OpenlookengClusterConfig::getOpenlookengClusterId, id);
            queryWrapper.eq(OpenlookengClusterConfig::getVersion, version);
            queryWrapper.eq(OpenlookengClusterConfig::getProKeyName, "discovery.uri");
            List<OpenlookengClusterConfig> configList = configService.list(queryWrapper);
            allConfigList.addAll(configList);
        });

        BigDecimal multiplyNum = new BigDecimal("100");

        allConfigList.forEach(a -> {
            try {
                String jsonStr = HttpUtil.get(a.getProValue() + Constant.URL_STATE_SUFFIX.getCode(), 1000);
                if (JSONUtil.isJson(jsonStr)) {
                    Map<String, Map> dataMap = JSONUtil.toBean(jsonStr, Map.class);
                    if (!dataMap.isEmpty()) {
                        dataMap.forEach((k, v) -> {
                            Ecs ecs = ecsList.stream().filter(t -> k.contains(t.getIp())).findFirst().orElse(null);
                            OpenlookengCluster openlookengCluster = clusterList.stream().filter(u -> u.getEcsId().equals(ecs.getId())).findFirst().get();
                            Integer nodeId = openlookengCluster.getId();
                            String cpuInfoListCacheKey = "clusterCacheEchart_cpuInfoList_" + nodeId;
                            String menInfoListCacheKey = "clusterCacheEchart_menInfoList_" + nodeId;
                            String diskInfoListCacheKey = "clusterCacheEchart_diskInfoList_" + nodeId;
                            List<EchartTimeDTO> cpuInfoList = cache.get(cpuInfoListCacheKey, List.class);
                            List<EchartTimeDTO> diskInfoList = cache.get(diskInfoListCacheKey, List.class);
                            List<EchartTimeDTO> menInfoList = cache.get(menInfoListCacheKey, List.class);
                            if (cpuInfoList == null) {
                                cpuInfoList = new ArrayList<>();
                            }
                            if (menInfoList == null) {
                                menInfoList = new ArrayList<>();
                            }
                            if (diskInfoList == null) {
                                diskInfoList = new ArrayList<>();
                            }
                            List<EchartTimeDTO> finalCpuInfoList = new ArrayList<>();
                            cpuInfoList.forEach(item -> {
                                EchartTimeDTO dto = new EchartTimeDTO();
                                BeanUtil.copyProperties(item, dto);
                                finalCpuInfoList.add(dto);
                            });
                            List<EchartTimeDTO> finalMenInfoList = new ArrayList<>();
                            menInfoList.forEach(item -> {
                                EchartTimeDTO dto = new EchartTimeDTO();
                                BeanUtil.copyProperties(item, dto);
                                finalMenInfoList.add(dto);
                            });
                            List<EchartTimeDTO> finalDiskInfoList = new ArrayList<>();
                            diskInfoList.forEach(item -> {
                                EchartTimeDTO dto = new EchartTimeDTO();
                                BeanUtil.copyProperties(item, dto);
                                finalDiskInfoList.add(dto);
                            });
                            BigDecimal cpu = new BigDecimal(v.getOrDefault("systemCpuLoad", "0").toString()).multiply(multiplyNum).setScale(2, RoundingMode.HALF_UP);
                            Map pools = (Map) v.getOrDefault("pools", new HashMap<>());
                            BigDecimal menPerCent = BigDecimal.ZERO;
                            if (pools.size() > 0) {
                                Map general = (Map) pools.getOrDefault("general", new HashMap<>());
                                BigDecimal maxBytes = new BigDecimal(general.getOrDefault("maxBytes", "1").toString());
                                BigDecimal freeBytes = new BigDecimal(general.getOrDefault("freeBytes", "0").toString());
                                BigDecimal menUsed = maxBytes.subtract(freeBytes); //已使用的内存
                                menPerCent = menUsed.divide(maxBytes, 4, RoundingMode.HALF_UP).multiply(multiplyNum);
                            }
                            Map<String, String> osInfo = iEcsService.getOsInfoFromCache(ecs);
                            EchartTimeDTO cpuDto = new EchartTimeDTO();
                            cpuDto.setType("cpu");
                            cpuDto.setNodeId(nodeId);
                            cpuDto.setCacheTime(new Date());
                            cpuDto.setValue(cpu);
                            EchartTimeDTO menDto = new EchartTimeDTO();
                            menDto.setType("men");
                            menDto.setNodeId(nodeId);
                            menDto.setCacheTime(new Date());
                            menDto.setValue(menPerCent);
                            String diskPercent = osInfo.getOrDefault("disk_percent", "");
                            BigDecimal disPerCent = BigDecimal.ZERO;
                            BigDecimal total = BigDecimal.ZERO;
                            if (StringUtils.isNotBlank(diskPercent)) {
                                List<String> perCentList = Arrays.asList(diskPercent.split("&"));
                                perCentList = perCentList.stream().filter(af -> !af.contains("se")).collect(Collectors.toList());
                                for (String aa : perCentList) {
                                    String val = aa.replaceAll("%", "");
                                    total = total.add(new BigDecimal(val));
                                }
                                disPerCent = total.divide(BigDecimal.valueOf(perCentList.size()), 4, RoundingMode.HALF_UP);
                            }
                            EchartTimeDTO diskDto = new EchartTimeDTO();
                            diskDto.setType("disk");
                            diskDto.setNodeId(nodeId);
                            diskDto.setCacheTime(new Date());
                            diskDto.setValue(disPerCent);
                            finalCpuInfoList.add(cpuDto);
                            finalMenInfoList.add(menDto);
                            finalDiskInfoList.add(diskDto);
                            cache.put(cpuInfoListCacheKey, finalCpuInfoList);
                            cache.put(menInfoListCacheKey, finalMenInfoList);
                            cache.put(diskInfoListCacheKey, finalDiskInfoList);
                        });
                    }
                }
            }
            catch (Exception e) {
                //log.error("cacheAllClusterInfo err discoveryUri :{},err:{}", a.getProValue(), e.getMessage());
            }
        });
    }

    @Override
    public OpenlookengCluster getByEcsId(Integer ecsId)
    {
        LambdaQueryWrapper<OpenlookengCluster> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OpenlookengCluster::getEcsId, ecsId);
        return this.getOne(queryWrapper);
    }
}
